#include <ev.h>

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <signal.h>

#include <stdlib.h>

#include "log.h"
#include "net.h"
#include "client.h"

#define APP_ID	"evd"
#define HOST	"127.0.0.1"
#define PORT	4000
#define BACKLOG 10

LOGGER(CONSOLE,"ev")

ev_io server_watcher;
ev_timer timeout_watcher;
ev_signal sigint_watcher;

struct rb_root clients = RB_ROOT;

void process_cb (EV_P_ ev_io *w, int revents)
{
	struct client * cl = get_client(&clients,w->fd);
        int need = BUF_LEN - cl->idx - 1;

        Log(1,"Data appeared: cl->idx = %i",cl->idx);

        int byte_read;
        byte_read = recv(w->fd,&(cl->data_buf[cl->idx]),need,MSG_PEEK);
        Log(1,"Byte read: %i",byte_read);

        if( byte_read > 0) {
            recv(w->fd,&(cl->data_buf[cl->idx]),byte_read,0);
            cl->idx += byte_read;

            if(BUF_LEN-1 == cl->idx) {
                Log(1,"%s",cl->data_buf);
                cl->idx = 0;
                memset(cl->data_buf,0,BUF_LEN);
            }
        } else if(0 == byte_read /* && ENOMSG == errno */) {
            Log_msg(1,"Data completed.");
            del_client(&clients,cl);
            close(w->fd);
            ev_io_stop(EV_A_ w);
            free(w);
        } else if(-1 == byte_read && EAGAIN != errno) {
		perror("recv");
	}
}

void server_cb (EV_P_ ev_io *w, int revents)
{
	Log_msg(1,"Client appeared");

	struct sockaddr_in s_addr;
	socklen_t s_addr_len = sizeof(struct sockaddr_in);
	int sock = accept(w->fd,(struct sockaddr*)&s_addr,&s_addr_len);

	ev_io *process_watcher = malloc(sizeof(ev_io));

	unblock(sock);

        struct client* new_client = add_client(&clients,sock);
        strncpy(new_client->name,inet_ntoa(*(struct in_addr*)&s_addr_len),NAMEBUF_LEN-1);
        Log(1,"Client addr: %s",new_client->name);

	ev_io_init (process_watcher, process_cb, sock, EV_READ);
	ev_io_start (loop, process_watcher);
}

void timeout_cb (EV_P_ ev_timer *w, int revents)
{

}

void sigpipe_handler(int sig)
{
	Log_msg(1,"SIGPIPE catched");
}

void sigint_cb(EV_P_ ev_signal *w, int revents)
{
	Log_msg(1,"SIGINT catched");
	ev_unloop(EV_A_ EVUNLOOP_ALL);
}

extern void test_clients();

int main (void)
{
	signal(SIGPIPE,sigpipe_handler); //triggers when remote writer closes connection

	Log_msg(1,"Start");

        struct sockaddr_in server_addr;
        if( -1 == init_addr(&server_addr,HOST,PORT)) {
		Log_msg(1,"Cannot init server address");
		return 1;
	}

	int server_socket;
	if( -1 == (server_socket = init_server_socket(&server_addr)) ) {
		Log_msg(1,"Cannot init server socket");
		return 1;
	}

	if(-1 == (listen(server_socket,BACKLOG))) {
		perror("listen");
		Log_msg(1,"Cannot listen socket");
		return 1;
	}

        //test_clients(1000000);
        //return 0;

	struct ev_loop *loop = ev_default_loop (0);

	ev_io_init (&server_watcher, server_cb, server_socket, EV_READ);
	ev_io_start (loop, &server_watcher);

	ev_signal_init(&sigint_watcher, sigint_cb, SIGINT);
	ev_signal_start(loop,&sigint_watcher);

	ev_timer_init (&timeout_watcher, timeout_cb, 3., 1.);
	ev_timer_start (loop, &timeout_watcher);

        Log_msg(1,"Starting loop");

	ev_loop (loop, 0);

	close(server_socket);

	Log(1,"Finish");

	return 0;
}
